﻿using System;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.Windows.Forms;

namespace RFServer.ServiceWCF
{
    /// <summary>
    /// Класс управления статусом WCF службы
    /// </summary>

    class ServiceStatus
    {
        private class Running
        {
            public bool isRunning { get; set; }

            public Running(bool isRunning)
            {
                this.isRunning = isRunning;
            }
        }

        private Running status;

        public ServiceStatus(bool isRunning)
        {
            status = new Running(isRunning);
        }

        public bool IsRunning()
        {
            bool result = false;

            lock (status)
            {
                result = status.isRunning;
            }

            return result;
        }

        public void Set(bool isRunning)
        {
            lock (status)
            {
                status.isRunning = isRunning;
            }
        }
    }

    /// <summary>
    /// Класс управления всеми WCF службами
    /// </summary>

    class ServiceControl
    {
        private static ServiceHost mainService;         // Служба TCP
        private static ServiceHost localService;        // Служба NamedPipe
        public static ServiceStatus Status { get; private set; }

        /// <summary>
        /// Инициализация двух служб - локальной (NamedPipe) и
        /// удаленной (TCP). Службы привязываются к портам/адресам
        /// и ожидают запуска
        /// </summary>

        static ServiceControl()
        {
            Setup.Log("[wcf]: Initializing services...");

            /* Инициализация основной службы-сервера */

            try
            {
                /* Базовые адреса службы */

                Uri baseAddress = new Uri(Setup.ServiceMainAddress);

                /* Регистрация типа службы во время выполнения */

                mainService = new ServiceHost(typeof(MainService), baseAddress);
            }
            catch (Exception e)
            {
                Setup.Log("[server]: Error creating main WCF service. Check App.config file", e);
            }

            /* Инициализация локальной службы для внутреннего администрирования */

            try
            {
                /* По умолчанию для NetNamedPipeBinding используется */
                /*  SecurityMode = Transport                         */
                /*  Transport.ProtectionLevel = EncryptAndSign       */
                /*  Клиентское удостоверение: Windows (только)       */

                Uri baseAddress = new Uri(Setup.ServiceLocalAddress);
                NetNamedPipeBinding binding = new NetNamedPipeBinding();

                binding.Security.Mode = NetNamedPipeSecurityMode.None;

                /* Регистрация типа службы во время выполнения */

                localService = new ServiceHost(typeof(LocalService), baseAddress);
                localService.AddServiceEndpoint(typeof(ILocalService), binding, "");
            }
            catch (Exception e)
            {
                Setup.Log("[local server]: Error creating local WCF service", e);
            }

            /* Установка статуса служб */

            Status = new ServiceStatus(false);
        }

        /// <summary>
        /// Запуск двух служб - локальной и удаленной
        /// </summary>
        /// <returns>
        /// true, если запуск обеих служб был успешен
        /// </returns>

        public static bool Start()
        {
            /* Проверка, чтобы службы были остановлены */

            if (Status.IsRunning())
                return false;

            try
            {
                /* Запуск основной службы-сервера */

                if (mainService == null)
                    return false;
                
                Setup.Log("[server]: Configured on " + Setup.ServiceMainAddress);
                Setup.Log("[server]: Starting...");

                /* Включение метаданных */

                //ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
                //smb.MetadataExporter = true;

                //service.Description.Behaviors.Add(smb);

                /* Запуск службы */

                mainService.Open();

                Setup.Log("[server]: Started");

                /* Запуск локальной службы для внутреннего администрирования */

                if (mainService == null)
                    return false;

                Setup.Log("[local server]: Configured on " + Setup.ServiceLocalAddress);
                Setup.Log("[local server]: Starting...");

                localService.Open();

                Setup.Log("[local server]: Started");

                /* Все службы запущены */

                Status.Set(true);

                return true;
            }
            catch (CommunicationException e)
            {
                Setup.Log("[wcf]: Communication error starting WCF service", e);
                return false;
            }
            catch (Exception e)
            {
                Setup.Log("[wcf]: Unknown error starting WCF service", e);
                return false;
            }
        }

        /// <summary>
        /// Остановка двух служб - локальной и удаленной
        /// </summary>

        public static void Stop()
        {
            /* Проверка, чтобы службы были запущены */

            if (!Status.IsRunning())
                return;

            /* Отмечаем, что все службы остановлены */

            Status.Set(false);

            /* Остановка основной службы-сервера */

            if (mainService == null)
                return ;

            Setup.Log("[server]: Stopping...");

            mainService.Close();

            Setup.Log("[server]: Stopped");

            /* Остановка локальной службы для внутреннего администрирования */

            if (localService == null)
                return;

            Setup.Log("[local server]: Stopping...");

            localService.Close();

            Setup.Log("[local server]: Stopped");
        }

        /// <summary>
        /// Остановка всех служб и завершение приложения
        /// (команда SHUTDOWN)
        /// </summary>

        public static void FullStop()
        {
            /* Проверка, чтобы службы были запущены */

            if (!Status.IsRunning())
                return;

            /* Остановка служб */

            ServiceControl.Stop();

            /* Завершение приложения                                  */
            /* (возможно только в случае, если это не Windows служба, */
            /* и была подана команда SHUTDOWN)                        */

            Application.Exit();
        }
    }
}
